/*
 * Copyright (c) 2020 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


#include "hx711_control.h"
#include "iot_gpio.h"
#include <stdio.h>
#include <sys/time.h>
#include "gpio_if.h"

#define GPIO_INPUT_PB14 (38) // data
#define GPIO_OUTPUT_PB15 (39) // clk
#define WEIGHT_NUMBER (16) // 采样个数
#define MEASURE_INTERVAL_MS (5) // 单次采样后休眠时间
#define TRANSFER_PERCENT (429.5) // AD值与体重的转换比例
#define INIT_WEIGHT (19433) // 皮重
#define SCALEFACTOR (1) // 比例系数
#define CONFIG_DELAY (2)  // 读AD值延时
#define CONFIG_AD_MAX (24) // AD读取个数
#define CONFIG_MI (1000000) // 微妙

static int g_init_weight = 0;

void  Hx711SetInitWeight(int weight)
{
    g_init_weight = weight;
}

static unsigned long GetMicrosecond(void)
{
    struct timeval tv;
    gettimeofday(&tv, NULL);

    return tv.tv_sec * CONFIG_MI + tv.tv_usec;
}

void Hx711InitRegisterIO(void)
{
    if (0 == GpioSetDir(GPIO_INPUT_PB14, GPIO_DIR_IN)) {
        printf("set gpio success!PB14\n");
    }
    if (0 == GpioSetDir(GPIO_OUTPUT_PB15, GPIO_DIR_OUT)) {
        printf("set gpio success!PB15\n");
    }
}

static unsigned int ReadValue(void)
{
    unsigned long count;
    unsigned char i;
    enum GpioValue value = GPIO_VAL_HIGH;
    GpioWrite(GPIO_OUTPUT_PB15, GPIO_VAL_LOW);
    count = 0;
    while (value == GPIO_VAL_HIGH) {
        GpioRead(GPIO_INPUT_PB14, &value);
    }
    for (i = 0; i < CONFIG_AD_MAX; i++) {
        GpioWrite(GPIO_OUTPUT_PB15, GPIO_VAL_HIGH);
        HAL_UDelay(CONFIG_DELAY);
        count = (count<<1);
        GpioWrite(GPIO_OUTPUT_PB15, GPIO_VAL_LOW);
        HAL_UDelay(CONFIG_DELAY);
        GpioRead(GPIO_INPUT_PB14, &value);
        if (value) {
            count++;
        }
    }
    GpioWrite(GPIO_OUTPUT_PB15, GPIO_VAL_HIGH);
    HAL_UDelay(CONFIG_DELAY);
    count = count^0x800000;
    GpioWrite(GPIO_OUTPUT_PB15, GPIO_VAL_LOW);
    HAL_UDelay(CONFIG_DELAY);
    return count;
}

/**
 * @brief  Bubble Sort,which is from small to large
*/
static void sort(float *buf, unsigned int length)
{
    int i, j;
    for (i = 0; i < length; i++) {
        for (j = 0; j < length - i - 1; j++) {
            if (buf[j] > buf[j+1]) {
                float tmp = buf[j];
                buf[j] = buf[j+1];
                buf[j+1] = tmp;
            }
        }
    }
}

static int FilteringData(void)
{
    unsigned int weightBuff[WEIGHT_NUMBER];
    int total = WEIGHT_NUMBER;
    int i;
    for (i = 0; i < total; i++) {
        weightBuff[i] = ReadValue();
        OS_MSleep(MEASURE_INTERVAL_MS);
    }
    sort(weightBuff, total);
    return weightBuff[(total-1) / 2];
}

int GetMeasurementWeight(float *value)
{
    // 精确到克
    int weight = (int)((float)(FilteringData() * 1.0) / TRANSFER_PERCENT - INIT_WEIGHT - g_init_weight);
    if (weight < 0) {
        weight = 0 - weight;
    }
    *value = (float)(weight * 0.001);
    return 1;
}
